package com.mnkjxy.beauty.view.manager;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;

import android.util.Log;

/**
 * 一个存放view集合的map集合，采用软引用的方式，优化内存
 * 
 * @author lqp
 * 
 */
public class MySoftMap<K, V> extends HashMap<K, V> {

	private static final String TAG = "MySoftMap";
	/**
	 * 定义一个存放软引用的集合,软引用指向具体的视图对象
	 */
	private HashMap<K, mySoftReference<K, V>> temp;
	private ReferenceQueue<V> queue;

	public MySoftMap() {
		temp = new HashMap<>();
		queue = new ReferenceQueue<>();
	}

	@Override
	public V put(K key, V value) {
		// TODO Auto-generated method stub
		// 创建了带队列的用于缓存软引用的队列
		mySoftReference<K, V> sr = new mySoftReference(key, value, queue);
		// 带标记的,用于删除temp中的元素

		temp.put(key, sr); // 视屏做法
		return null;
		// return (V) temp.put(key, sr);
	}

	/**
	 * 
	 * 软引用里面的对象有可能被销毁，如果被销毁的话，通过get方法将返回空，
	 * 但是这个引用对象还将是存在的，软引用优先销毁创建时间长的对象，对于正在使用的不会被回收
	 * 
	 * @return,如果被回收将返回空
	 */

	@Override
	public V get(Object key) {

		clearSoftReference();
		// 获取具体视图的软引用
		mySoftReference<K, V> sr = temp.get(key);
		if (sr != null) {
			// 获取具体的视图对象，有可能为空
			Log.i(TAG, "使用自定义集合,视图没有被内存回收");
			return sr.get();
		}
		Log.i(TAG, "使用自定义集合,视图已经被内存回收");
		return null;

	}

	/**
	 * 判断软引用集合中的引用指向的对象是否还存在，如果被回收了，返回false
	 */
	@Override
	public boolean containsKey(Object key) {
		// TODO Auto-generated method stub
		// temp中有，可能只是空的软引用，因此
		// 清除空的软引用
		return get(key) != null;

	}

	/**
	 * 移除队列中的软引用
	 */
	public void clearSoftReference() {
		// 方式一：循环temp，逐一判断是否有手机，存在问题：如果当前内存够用，循环无用
		// 方式二：GC知道把那个袋子的手机给回收了，利用GC，让其记录曾经被偷的手机（存入到集合中）
		// 如果能够控制该集合，再循环该集合，里面存放的一定被回收了
		// 轮询此队列，查看是否存在可用的引用对象。
		// 如果存在一个立即可用的对象，则从该队列中"移除"此对象并返回。
		// 否则此方法立即返回 null。
		mySoftReference<K, V> poll = (mySoftReference<K, V>) queue.poll();

		while (poll == null) {
			poll = (mySoftReference<K, V>) queue.poll();
			temp.remove(poll.key);
		}
	}

	/**
	 * 增强的软引用,真加一个key,方便从集合中删除
	 * 
	 * @author lqp
	 * 
	 * @param <K>
	 * @param <V>
	 */
	private class mySoftReference<K, V> extends SoftReference<V> {
		private K key;

		public mySoftReference(K key, V r, ReferenceQueue<V> q) {
			super(r, q);
			// TODO Auto-generated constructor stub
			this.key = key;
		}
	}
}
